home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / biblio / bibtex / mac / macbibtex11.hqx / 0.99c Sources / MacBibTeX 0.99c v1.1.sit / MacBibTex 0.99c V1.1 / Pstr.c < prev    next >
Text File  |  1987-10-23  |  7KB  |  338 lines

  1. /*
  2. **    Pascal string, C string, and formatting utility routines
  3. **
  4. **    This module contains routines for
  5. **
  6. **        +    Copying, concatenating, and comparing Macintosh
  7. **            pascal-style (leading byte contains length) strings
  8. **
  9. **        +    Converting Macintosh pascal-style strings to/from C-style
  10. **            (NUL terminated) strings
  11. **
  12. **        +    Formatting numbers as pascal-style strings
  13. **
  14. **        +    Performing substitutions on pascal-style strings (formatting)
  15. **
  16. **    Best of all, they're free!
  17. **
  18. **    Written by Alan B. Mimms, 22 Oct, 1987
  19. **
  20. **    Permission is hereby granted to freely duplicate, modify, disseminate,
  21. **    and otherwise distribute this software until your heart's content.
  22. **    No copyright is claimed.  However, I am not responsible for the
  23. **    performance of this software and may not be held accountable for
  24. **    any failure of the software to perform in any way under any circum-
  25. **    stances.
  26. */
  27.  
  28. #include "Pstr.h"
  29.  
  30. /*
  31. **    Uncomment the following line and link with stdio and MacTraps
  32. **    (LightspeedC, anyway) to run the test stuff for numfmt ()...
  33. **
  34. **    #define DEBUGMAIN
  35. */
  36.  
  37.  
  38. /*
  39. **    Compare two pascal strings, returning a zero if they're equal,
  40. **    a negative number if s1 is less than s2, or
  41. **    a positive number if s1 is greater than s2.
  42. */
  43.  
  44. int pstrcmp (s1, s2)
  45.  
  46.     register uchar *s1, *s2;
  47.  
  48. {
  49.     register int i;
  50.     register int c;
  51.     int len = *s1 < *s2 ? *s1 : *s2;
  52.  
  53.     for (i = 1; i <= len; ++i)
  54.         if (c = s1 [i] - s2 [i]) return (c);
  55.  
  56.     if (*s1 == *s2)
  57.         return (0);
  58.     else if (*s1 < *s2)
  59.         return (-1);
  60.     else
  61.         return (1);
  62. }
  63.  
  64.  
  65. /*
  66. **    Copy pascal string "s2" into the buffer to which "s1" points.
  67. **    NOTE: It is assumed that the buffer (s1) is large enough for
  68. **    the entire string "s2".  Returns "s1".
  69. */
  70. uchar *pstrcpy (s1, s2)
  71.  
  72.     register uchar *s1, *s2;
  73.  
  74. {
  75.     register int i;
  76.  
  77.     for (i = 0; i <= *s2; ++i) s1 [i] = s2 [i];
  78.     return (s1);
  79. }
  80.  
  81.  
  82. /*
  83. **    Concatenate the pascal string "s2" onto the end of the current
  84. **    contents of the pascal string "s1".  Returns "s1".
  85. */
  86. uchar *pstrcat (s1, s2)
  87.  
  88.     register uchar *s1, *s2;
  89.  
  90. {
  91.     register int i;
  92.  
  93.     for (i = 1; i <= s2 [0]; ++i)
  94.         s1 [++s1 [0]] = s2 [i];
  95.  
  96.     return (s1);
  97. }
  98.  
  99.  
  100. /*
  101. **    Copy C-style (NUL terminated) string "c" to buffer to which "p"
  102. **    points as a pascal-style (leading byte contains length) string.
  103. **    Returns "p".
  104. */
  105. uchar *cpyc2p (p, c)
  106.  
  107.     register uchar *p, *c;
  108.  
  109. {
  110.     for (*p = 0; *c; ++c, ++*p)
  111.         p [*p] = *c;
  112.  
  113.     return (p);
  114. }
  115.  
  116.  
  117. /*
  118. **    Copy pascal-style string "p" into buffer to which "c" points as a
  119. **    C-style string.  Returns "c".
  120. */
  121. uchar *cpyp2c (c, p)
  122.  
  123.     register uchar *c, *p;
  124.  
  125. {
  126.     register int len;
  127.     uchar *oldc;
  128.  
  129.     for (oldc = c, len = *p++; len; --len)
  130.         *c++ = *p++;
  131.  
  132.     *c = 0;
  133.     return (oldc);
  134. }
  135.  
  136.  
  137. /*
  138. **    Format the number "n" in specified "radix" (2..16) using "width" as the
  139. **    desired field width.  If "width" is greater than zero, leading
  140. **    blanks will be inserted to fill the result string to "width"
  141. **    bytes in length.  If "width" is less than zero, the leading zeroes
  142. **    will be inserted instead of leading blanks.  If "width" is zero,
  143. **    the minimum field width necessary to represent the value (i.e.,
  144. **    with no leading zeroes or leading blanks) will be used.  If "radix"
  145. **    is zero, the default radix 10 will be used.  Places the formatted
  146. **    number into the buffer to which "string" points (at least 34 bytes
  147. **    should be allocated for it -- you can use typedef "numbuf") as a
  148. **    pascal-style string.  Returns "string".
  149. */
  150. unsigned char *numfmt (string, n, width, radix)
  151.  
  152.     register uchar *string;
  153.     register long n;
  154.     int width, radix;
  155.  
  156. {
  157.     register int w;
  158.     int wasneg, realwidth = width;
  159.     long realN = n;
  160.     static char digits [] = "0123456789ABCDEF";
  161.     
  162.     if (!radix) radix = 10;
  163.     if (!width)    width = 33;
  164.     string [0] = w = width < 0 ? -width : width;
  165.  
  166.     if (wasneg = (n < 0)) {
  167.         n = -n;
  168.         wasneg = (width > 0);
  169.     }
  170.  
  171.     for ( ; w; --w) {
  172.         uchar c = digits [n % radix];
  173.  
  174.         if (!n && c == '0')
  175.             if (wasneg) {
  176.                 c = '-';
  177.                 wasneg = 0;
  178.             } else if (w != string [0] && width > 0) c = ' ';
  179.  
  180.         string [w] = c;
  181.         n /= radix;
  182.     }
  183.  
  184.     if (!realwidth) {
  185.         register int i, j;
  186.  
  187.         for (i = 1; i < string [0]; ++i)
  188.             if (string [i] != ' ') break;
  189.  
  190.         for (j = 1; i <= string [0]; ++i, ++j)
  191.             string [j] = string [i];
  192.  
  193.         string [0] = j - 1;
  194.     } else if (n || wasneg)
  195.         for (w = 1; w <= string [0]; ++w)
  196.             string [w] = '*';
  197.     else if (realwidth < 0 && realN < 0)
  198.         string [1] = '-';
  199.  
  200.     return (string);
  201. }
  202.  
  203.  
  204. /*
  205. **    Substitutes within the pascal-style string "result" the leftmost
  206. **    occurrence of the substring (pascal-style) "target" with the new
  207. **    substring (again, pascal-style) "source", and returns "result".
  208. */
  209. uchar *mungpstr (result, target, source)
  210.  
  211.     uchar *result, *target, *source;
  212.  
  213. {
  214.     register int r, delta;
  215.  
  216.     /* Find position of target in result */
  217.  
  218.     for (r = 1; r <= result [0] - target [0] + 1; ++r)
  219.     {
  220.         register int t;
  221.  
  222.         for (t = 1; t <= target [0]; ++t)
  223.  
  224.             if (target [t] != result [r + t - 1])
  225.                 goto NotThisTime;
  226.  
  227.         goto FoundTarget;
  228.  
  229. NotThisTime: ;
  230.     }
  231.  
  232.     return (result);            /* No target string found in result */
  233.  
  234. FoundTarget:
  235.     delta = source [0] - target [0];
  236.  
  237.     if (delta > 0)
  238.     {
  239.         register int k;
  240.  
  241.         for (k = result [0]; k >= r; --k)
  242.             result [k + delta] = result [k];
  243.     }
  244.     else if (delta < 0)
  245.     {
  246.         register int k;
  247.  
  248.         for (k = r + source [0]; k <= result [0]; ++k)
  249.             result [k] = result [k - delta];
  250.     }
  251.  
  252.     result [0] += delta;
  253.  
  254.     for (delta = 1; delta <= source [0]; ++delta)
  255.         result [r++] = source [delta];
  256.  
  257.     return (result);
  258. }
  259.  
  260.  
  261. /*
  262. **    Calls "mungpstr" repeatedly on the pascal-style string "msg"
  263. **    with successive pairs of parameters for the "target" and "source"
  264. **    strings.  Calling sequence (in reality) is like this:
  265. **
  266. **        Str255 buf;
  267. **        numbuf nbuf [34];
  268. **
  269. **        mungmsg (
  270. **            pstrcpy (buf, "\PReplace foo with bar and X with a hex number"),
  271. **            "\Pfoo", "\Pbar",
  272. **            "\PX", numfmt (nbuf, 12345678L, 0, 16),
  273. **            (uchar *) 0);
  274. **
  275. **    This call results in the string
  276. **
  277. **        "Replace bar with bar and BC614E with a hex number"
  278. */
  279. uchar *mungmsg (msg, mungitems)
  280.  
  281.     uchar *msg, *mungitems;
  282.  
  283. {
  284.     register uchar **p;
  285.  
  286.     for (p = &mungitems; *p; p += 2) mungpstr (msg, p [0], p [1]);
  287.     return (msg);
  288. }
  289.  
  290.  
  291. /*
  292. **    This is used during debugging...
  293. */
  294. #ifdef DEBUGMAIN
  295. #include <stdio.h>
  296.  
  297. /* Put out a pascal-style string to stdout */
  298. static void putps (p)
  299.  
  300.     char *p;
  301.  
  302. {
  303.     int i;
  304.  
  305.     for (i = 1; i <= p [0]; ++i)
  306.         putchar (p [i]);
  307.  
  308.     putchar ('\n');
  309. }
  310.  
  311. #define TEST(v,w)    numfmt(s,(v),(w),10);printf("%ld@%d=",(long)(v),(w));putps(s);
  312.  
  313. main ()
  314.  
  315. {
  316.     uchar s [256];
  317.  
  318.     /* Test for faulty leading zero suppression */
  319.     TEST (-3000789L, -12);
  320.     TEST (-3000789L, 12);
  321.     TEST (-3000789L, 0);
  322.     TEST (3000789L, -12);
  323.     TEST (3000789L, 12);
  324.     TEST (3000789L, 0);
  325.  
  326.     /* Test for correct display */
  327.     TEST (-123456789L, -12);
  328.     TEST (-123456789L, 12);
  329.     TEST (-123456789L, 0);
  330.     TEST (123456789L, -12);
  331.     TEST (123456789L, 12);
  332.     TEST (123456789L, 0);
  333.     TEST (0L, -12);
  334.     TEST (0L, 12);
  335.     TEST (0L, 0);
  336. }
  337. #endif DEBUGMAIN
  338.